package edu.thu.thss.yxy.configuration;

import java.io.*;
import java.util.Properties;
import java.util.Set;

import edu.thu.thss.yxy.util.Logger;

public class ConfigurationManager {
	/**
	 * Our logger.
	 */
	private final static Logger logger = Logger
			.getLogger(ConfigurationManager.class);

	/**
	 * The <code>Properties</code> instance which stores the property name-value
	 * associations of this <code>ConfigurationStore</code> instance and which
	 * is effectively adapted by this instance to
	 * <code>ConfigurationStore</code>.
	 */
	private static Properties properties = new Properties();
	private static Properties newProperties = new Properties();

	final static String userDir = System.getProperty("user.dir");

	/**
	 * Loads the properties from the configuration file
	 */
	public static void loadProperties() {
		File configFile = getConfigurationFile();
		try {
			InputStream in = new BufferedInputStream(new FileInputStream(
					configFile));
			properties.load(in);
		} catch (Exception ex) {
			logger.error("Error parsing configuration file", ex);
		}
	}

	/**
	 * Get the gonfiguration file.
	 * 
	 * @return the configuration File
	 */
	protected static File getConfigurationFile() {
		try {
			String pFileName = "GoPhone.properties";
			File configFileInWorkingDir = new File(userDir
					+ "/resources/config/" + pFileName);

			if (configFileInWorkingDir.exists()) {
				logger.trace("Configuration file found in work dir.");
				return configFileInWorkingDir;
			}

			// check in user.home directory
			File configDir = new File(System.getProperty("user.home")
					+ File.separator + ".gophone");

			File configFileInUserHomeDir = new File(configDir, pFileName);

			if (configFileInUserHomeDir.exists()) {
				logger.trace("Config file found in userhome");
				return configFileInUserHomeDir;
			}

			// If we are in a jar - copy config file from jar to user home.
			logger.trace("Copying config file.");

			configDir.mkdirs();
			InputStream in = ConfigurationManager.class.getClassLoader()
					.getResourceAsStream(pFileName);

			if (in == null) {
				configFileInUserHomeDir.createNewFile();
				return configFileInUserHomeDir;
			}
			BufferedReader reader = new BufferedReader(
					new InputStreamReader(in));

			PrintWriter writer = new PrintWriter(new FileWriter(
					configFileInUserHomeDir));

			String line = null;
			System.out.println("Copying properties file:");
			while ((line = reader.readLine()) != null) {
				writer.println(line);
				logger.debug(line);
			}
			writer.flush();
			return configFileInUserHomeDir;
		} catch (IOException ex) {
			logger.error("Error creating config file", ex);
			return null;
		}
	}

	/**
	 * Set configuration property
	 * 
	 * @param propertyName
	 *            name of property
	 * @param propertyValue
	 *            value of property
	 */
	public static void setProperty(String propertyName, String propertyValue) {
		if (propertyValue == null)
			propertyValue = "";

		if (System.getProperty(propertyName) == null)
			newProperties.put(propertyName, propertyValue);

		System.setProperty(propertyName, propertyValue);
		properties.put(propertyName, propertyValue);
	}

	/**
	 * Store the current properties values in the configuration file
	 */
	public synchronized static void storeProperties() {
		File configFile = getConfigurationFile();
		try {
			OutputStream fos = new FileOutputStream(configFile);
			properties.store(fos, null);
		} catch (IOException ex) {
			logger.error("Error storing configuration file", ex);
		}
	}

	/*
	 * Implements ConfigurationStore#getProperty(String). If this
	 * ConfigurationStore contains a value associated with the specified
	 * property name, returns it. Otherwise, searches for a system property with
	 * the specified name and returns its value.
	 */
	public static String getProperty(String name) {
		String value = (String) properties.get(name);
		return (value != null) ? value : System.getProperty(name);
	}

	/*
	 * Implements ConfigurationStore#getPropertyNames().
	 */
	public String[] getPropertyNames() {
		synchronized (properties) {
			Set<Object> propertyNames = properties.keySet();
			return propertyNames.toArray(new String[propertyNames.size()]);
		}
	}

	/*
	 * Implements ConfigurationStore#isSystemProperty(String). Considers a
	 * property to be system if the system properties contain a value associated
	 * with its name.
	 */
	public boolean isSystemProperty(String name) {
		return (System.getProperty(name) != null);
	}

	public static Properties getProperties() {
		return properties;
	}
}
